package com.origin.learn.redisson;

import com.alibaba.fastjson.JSONObject;
import jodd.io.findfile.FindFile;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
import org.junit.Test;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description:
 * @Date: 2020/2/11
 * @Time: 16:18
 * @Created by:   dingtao
 * @Modified by:
 * @Modified at:
 */
public class RedissonUtil {

    @Test
    public void test222(){
//        key=111
//        key='xx'
//        key =111
//        key = 111
//        key ='xx'
//        key = 'xxx'
//        key like'xx'
//        key like 'xxx'
//
//        contains ( name, 'dingtao')
//        [a-zA-Z_]+


        String sql = "( name like 'dingtao k=value' or age = '16' and(location = 'sh'))and time >='141241' and time < '12412'";
//        Pattern pattern = Pattern.compile("[a-zA-Z_]+\\slike\\s*[^]");
//        String sql = "( name like 'dingtao' and age = '16' and(location = 'sh and key = \"value\"'))and(time >='141241' and time < '12412')";
        List<String> res= splitWithBrackets(sql);
        res.forEach(System.out::println);
        List<String> result = res.stream().map(this::getConditionPart).flatMap(Collection::stream).collect(Collectors.toList());
        result.forEach(x->{
            System.out.println("*****************************");
            System.out.println(JSONObject.toJSONString(x));
        });
        System.out.println("\n\n\n\n");
        result.forEach(RegexHelper::testRegex);
//        System.out.println(JSONObject.toJSON(getNeedHighlightFields(sql)));
    }




    public final static class RegexHelper{
        /**
         * 需要转化为星环查询语句的正则表达式
         */
        private static String[] NEED_TRANSFORM_TO_TRANSWARP_PATTERN = {
                //key like'value'
                //key like 'value'
                "(?<fieldName>[a-zA-Z]+)\\s+like\\s?(?<value>'[^']+')",
                //key like"value"
                //key like "value"
                "(?<fieldName>[a-zA-Z]+)\\s+like\\s?(?<value>\"[^\"]+\")",
                //key = 'value', key= 'value', key ='value', key='value'
                "(?<fieldName>[a-zA-Z]+)\\s?=\\s?(?<value>'[^']+')",
                "(?<fieldName>[a-zA-Z]+)\\s?=\\s?(?<value>\"[^\"]+\")",
                // key=111 ...
                "(?<fieldName>[a-zA-Z]+)\\s?=\\s?(?<value>\\d+)",
        };
        private static Pattern[] PATTERNS=null;
        static {
            PATTERNS = new Pattern[NEED_TRANSFORM_TO_TRANSWARP_PATTERN.length];
            for (int i = 0; i < NEED_TRANSFORM_TO_TRANSWARP_PATTERN.length; i++) {
                PATTERNS[i] = Pattern.compile(NEED_TRANSFORM_TO_TRANSWARP_PATTERN[i]);
            }
        }

        public static Map<String, Object> testRegex(String var){
            Map<String, Object> result = new HashMap<>(2);
            for (int i = 0; i < NEED_TRANSFORM_TO_TRANSWARP_PATTERN.length; i++) {
                if (var.matches(NEED_TRANSFORM_TO_TRANSWARP_PATTERN[i])){
                    try {
                        Matcher matcher = PATTERNS[i].matcher(var);
                        result.put("fieldName", matcher.group("fieldName"));
                        result.put("value", matcher.group("value"));
                        break;
                    }catch (Exception e){

                    }

                }
            }

            return result;
        }
    }

//    private

    @Test
    public void testpattern(){
        String pat = "(?<fieldName>[a-zA-Z_]+)\\s?=\\s?(?<value>'[^']+')";
//        String pattern = "([a-zA-Z]+)\\s+(like)\\s?('[^']+')";
        Pattern pattern1 = Pattern.compile(pat);
        String x = "eqpt_device_type='/BusinessApplication/BusinessRiskControlSystem'";
        System.out.println(x.matches(pat));
        Matcher matcher = pattern1.matcher(x);
        matcher.find();
        System.out.println(matcher.group("fieldName"));
//        System.out.println(matcher.group("paramType"));
        System.out.println(matcher.group("value"));
    }

    private Map<String, Object> replace(String var){
        System.out.println(var);
        String[] patterns = {
                "(a-zA-Z)+\\slike\\s'(^')+'"
        };
        for (String pattern : patterns) {
            System.out.println(var.matches(pattern));
        }
        return null;
    }

    public List<String> splitWithBrackets(String var){

        List<String> withoutSqureList = new LinkedList<>();
        char[] chars = var.toCharArray();
        Stack<Character> stack = new Stack<>();
        Stack<Character> helpToReverseStack = new Stack<>();
        for (int i = 0; i < chars.length; i++) {
            char temp = chars[i];
            if (temp!=')'){
                stack.push(temp);
            }
            else {
                helpToReverseStack.clear();
                char peek = stack.pop();
                while (peek!='('){
                    helpToReverseStack.push(peek);
                    peek = stack.pop();
                }
                char[] sqlChars = new char[helpToReverseStack.size()];
                for (int j = 0; j < sqlChars.length; j++) {
                    sqlChars[j] = helpToReverseStack.pop();
                }
                withoutSqureList.add(new String(sqlChars));
            }
        }
        if (!stack.isEmpty()){
            char[] sqlChars = new char[stack.size()];
            for (int i = sqlChars.length-1; i >=0 ; i--) {
                sqlChars[i] = stack.pop();
            }
            withoutSqureList.add(new String(sqlChars));
        }
        return withoutSqureList;
    }

    /**
     * 获得var中第一个满足key = value, key like value格式的片段
     * @param var
     * @return
     */
    private List<String> getConditionPart(String var){
        var = var.trim();
        if ("and".equals(var)||"or".equals(var)){
            return new ArrayList<>();
        }
        // 去除字符串开头的 and
        if (var.startsWith("and ")){
            var = var.substring(4);
        }else if (var.startsWith("or ")){
            var = var.substring(3);
        }
        if (var.length()==0){
            return new ArrayList<>();
        }

        Stack<Character> stack = new Stack<>();
        char[] helper;
        boolean flag = false;
        for (int i = 0; i < var.length(); i++) {
            char temp = var.charAt(i);
            if (temp=='\''||temp=='"'){
                stack.push(temp);
                if (!stack.isEmpty()&&stack.peek()!='\\'){
                    if (!flag){
                        //暂时还未放入查询值的左引号
                        flag = true;
                    }
                    else {
                        break;
                    }
                }
            }else {
                stack.push(temp);
            }
        }
        helper = new char[stack.size()];
        for (int j = stack.size()-1; j >=0 ; j--) {
            helper[j] = stack.pop();
        }
        String conditionPart = new String(helper);

        // 存放结果的列表
        List<String> result;
        result = Stream.of(conditionPart).collect(Collectors.toList());
        var = var.substring(conditionPart.length());
        List<String> sub = getConditionPart(var);
        if (sub.size()!=0) {
            result.addAll(sub);
        }
        return result;
    }

    /**
     * 返回where条件语句中的字段名称，以及经过es 高亮显示查询后的sql语句
     * @param likeParams key1 = value1, key2 like 'value2'这种形式的where条件语句
     * @return
     */
    private Map<String, Object> getNeedHighlightFields(String likeParams){
        String[] sp1 = likeParams.split("and");
        List<String> equalOrLike = getNeedTransformToTranswarpSqlFields(sp1);
        System.out.println("需要转换的:"+JSONObject.toJSON(equalOrLike));
        String temp = likeParams;
        for (String s : equalOrLike) {
            String replace = sqlToTranswarpHighLight(s, "highlightStyle");
            temp = temp.replaceAll(s, replace);
        }
        System.out.println("end: "+temp);


        Map<String, Object> result = new HashMap<>(2);
        List<String> fields = new ArrayList<>();
        result.put("fields", fields);
        result.put("sql", likeParams);


        return result;
    }

    /**
     * 获取需要进行星环es转化的字段列表
     * @param var
     * @return
     */
    private List<String> getNeedTransformToTranswarpSqlFields(String[] var){
        List<String> list = new ArrayList<>();
        for (String str : var) {
            if(str.contains(" = ")||str.contains(" like ")){
                while (true){
                    boolean hasMoreSqure = false;
                    str = str.trim();
                    if (str.startsWith("(")){
                        str = str.substring(1);
                        hasMoreSqure = true;
                    }
                    if (str.endsWith(")")){
                        str = str.substring(0, str.length()-1);
                        hasMoreSqure = true;
                    }
                    if (!hasMoreSqure){
                        break;
                    }
                }
                list.add(str);
            }
        }
        return list;
    }

    /**
     * 将普通sql语句转化为星环es的高亮查询语句
     * @param sql
     * @param highLightStyle
     * @return
     */
    private String sqlToTranswarpHighLight(String sql, String highLightStyle){
        String result = "";
        String[] sqlSplit=null;
        if (sql.contains(" = ")){
            sqlSplit = sql.split(" = ");
        }else if(sql.contains(" like ")){
            sqlSplit = sql.split("like");
        }
        if (sqlSplit.length==2){
            String fieldName = sqlSplit[0].trim();
            String value = sqlSplit[1].trim();
            if (fieldName.startsWith("(")&&!fieldName.endsWith(")")){
                fieldName =  fieldName.substring(1);
                value = value.substring(0, value.length()-1);
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(" contains (").append(fieldName).append(", ").append(value)
                    .append(", 'highlight', '<idss-span style=\"").append(highLightStyle).append("\">, ")
                    .append("'</idss-span>') ");
            result = stringBuilder.toString();
        }
        return result;
    }

    @Test
    public void test2(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("dsagadsgadsgads");
        String a = stringBuilder.toString();
        System.out.println(a);
        stringBuilder = null;
        System.out.println(a);

    }

    public List<Map<String, String>> genEvents(){
        List<Map<String, String>> events = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            events.add(genEvent());
        }
        return events;
    }

    @Test
    public void test(){


        List<Map<String, String>> events = genEvents();
        List<Map<String, String>> logs = genLogs(events);

        String eventSql = "BATCHINSERT INTO security_event ( KEYS ) BATCHVALUES ( VALS );";
        String logSql = "BATCHINSERT INTO security_log ( KEYS ) BATCHVALUES ( VALS );";
        gen(eventSql, events);
        gen(logSql, logs);

        int y =1;

    }

    public void gen(String sql, List<Map<String, String>> events){
        List<String> k1 = new ArrayList<>();
        k1.addAll(events.get(0).keySet());

        StringBuilder ksb = new StringBuilder();
        for (int i = 0; i < k1.size(); i++) {
            ksb.append(k1.get(i));
            if (i<k1.size()-1){
                ksb.append(", ");
            }
        }
        sql = sql.replaceAll("KEYS", ksb.toString());

        List<String> stemp = new ArrayList<>(events.size());

        for (Map<String, String> event: events) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("values (");
            for (int i = 0; i < k1.size(); i++) {
                stringBuilder.append("'").append(event.get(k1.get(i))).append("'");
                if (i<k1.size()-1){
                    stringBuilder.append(", ");
                }
            }
            stringBuilder.append(")");
            stemp.add(stringBuilder.toString());
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < stemp.size(); i++) {
            stringBuilder.append(stemp.get(i));
            if (i<stemp.size()-1){
                stringBuilder.append(", ");
            }
        }
        sql = sql.replaceAll("VALS", stringBuilder.toString());

        System.out.println(sql);

    }

//    create_time,rule_name,risk_score,event_description,severity_name,event_device_type,dst_ip,warn_status,src_ip,event_type,internal_event,event_name,
    public Map<String, String> genEvent(){
        String create_time = getRangeTimeStamp();
        String a1 = getRangeTimeStamp();
        String a2 = getRangeTimeStamp();
        String a3 = getRangeTimeStamp();
        Map<String, String> event = new HashMap<>();
        event.put("id", UUID.randomUUID().toString());
        event.put("org_create_time", a1+","+a2+","+a3);
        event.put("severity", serv.get(new Random().nextInt(serv.size()-1)));
        String oid = UUID.randomUUID().toString() + ","+UUID.randomUUID().toString() + "," +UUID.randomUUID().toString();
        event.put("org_log_id", oid);
        event.put("risk_type", eventname.get(new Random().nextInt(eventname.size()-1)));
        event.put("create_time", create_time);
        event.put("rule_name", eventname.get(new Random().nextInt(eventname.size()-1)));
        event.put("risk_score", String.valueOf(new Random().nextInt(5)));
//        event.put("event_technique_type", "/System_Compromise/Policy_Breach");
        event.put("event_description", eventname.get(new Random().nextInt(eventname.size()-1)));
//        event.put("severity_name", "严重");
        event.put("event_device_type", edt.get(new Random().nextInt(edt.size()-1)));
        event.put("dst_ip", "172.16.0.85");
        event.put("warn_status", "0");
        event.put("src_ip", "172.16.0.12");
        event.put("event_type", "/NetThreatAnalysis/NetIntrusion/MalwareAttack");
        event.put("internal_event", "1");
        event.put("event_name", eventname.get(new Random().nextInt(eventname.size()-1)));
        event.put("event_nums", "5");
        event.put("event_model_source", "/RuleEngine/OffLine");
        event.put("alarm_last_time", getMax(a1,a2,a3));
        event.put("alarm_first_time", getMin(a1, a2, a3));
        event.put("username", usernames.get(new Random().nextInt(usernames.size()-1)));
        event.put("src_asset_type", "src_asset_type");
        event.put("dst_asset_type", "dst_asset_type");
        event.put("domain", domain.get(new Random().nextInt(domain.size()-1)));
        event.put("system", system.get(new Random().nextInt(system.size()-1)));
        event.put("src_network_domain", src_network_domain.get(new Random().nextInt(src_network_domain.size()-1)));
        event.put("dst_network_domain", dst_network_domain.get(new Random().nextInt(dst_network_domain.size()-1)));
        event.put("src_asset_dept", src_asset_dept.get(new Random().nextInt(src_asset_dept.size()-1)));
        event.put("policy_name", policy_name.get(new Random().nextInt(policy_name.size()-1)));
        event.put("index_date", INDEX_DATE);

        return event;
    }

    public String getMax(String a, String b, String c){
        String max = a;
        if (Long.parseLong(b)>Long.parseLong(max)){
            max = b;
        }
        if (Long.parseLong(c)>Long.parseLong(max)) {
            max = c;
        }
        return max;
    }
    public String getMin(String a, String b, String c){
        String min = a;
        if (Long.parseLong(b)<Long.parseLong(min)){
            min = b;
        }
        if (Long.parseLong(c)<Long.parseLong(min)){
            min = c;
        }
        return min;
    }


    public List<Map<String, String>> genLogs(List<Map<String, String>> events){
        List<Map<String, String>> logs = new ArrayList<>();

        events.forEach(event->{
            logs.addAll(genLog(event.get("org_log_id"), event.get("org_create_time"), event.get("risk_type")));
            event.remove("org_create_time");
        });
        return logs;
    }

    public static String INDEX_DATE = "20200219";

    public static List<String> usernames = Stream.of("yidian", "u_zhujianwei", "u_yx_monijigou", "u_TransWarp_Sync").collect(Collectors.toList());
    public static List<String> db_name = Stream.of("message", "users", "click_infos", "unsafe").collect(Collectors.toList());
    public static List<String> eventname = Stream.of("account_abnormal", "try_to_thief_data", "multi_ip_login", "idss").collect(Collectors.toList());
    public static List<String> serv = Stream.of("info", "low", "medium", "high", "critical").collect(Collectors.toList());
    public static List<String> edt = Stream.of("/Application/WEBServer", "/VPN").collect(Collectors.toList());
    public static List<String> ips = Stream.of("172.16.0.12", "10.10.0.172", "192.16.0.33", "174.16.0.88", "172.16.0.139").collect(Collectors.toList());
    public static List<String> domain = Stream.of("domain1", "domain2", "domain3", "domain4", "domain5").collect(Collectors.toList());
    public static List<String> url = Stream.of("url1", "url2", "url3", "url4", "url5").collect(Collectors.toList());
    public static List<String> status = Stream.of("status1", "status2", "status3", "status4", "status5").collect(Collectors.toList());
    public static List<String> dst_port = Stream.of("1001", "2002", "3333", "4444", "5555").collect(Collectors.toList());
    public static List<String> system = Stream.of("centos6", "centos7", "ubuntu", "win10", "winserver").collect(Collectors.toList());
    public static List<String> src_network_domain = Stream.of("snd1", "snd2", "snd3", "snd4", "snd5").collect(Collectors.toList());
    public static List<String> dst_network_domain = Stream.of("dnd1", "dnd2", "dnd3", "dnd4", "dnd5").collect(Collectors.toList());
    public static List<String> src_asset_dept = Stream.of("sadept1", "sadept2", "sadept3", "sadept4").collect(Collectors.toList());
    public static List<String> policy_name = Stream.of("policy_name1", "policy_name2", "policy_name3", "policy_name4").collect(Collectors.toList());

    public List<Map<String, String>> genLog(String orgid, String create_time, String riskType){
        String[] orgID = orgid.split(",");
        String[] ct = create_time.split(",");
        List<Map<String, String>> logs = new ArrayList<>(3);
        for (int i = 0; i < orgID.length; i++) {

            Map<String, String> log = new HashMap<>();
            log.put("id", orgID[i]);
            log.put("url", url.get(new Random().nextInt(url.size()-1)));
            log.put("status", status.get(new Random().nextInt(status.size()-1)));
            log.put("dst_port", dst_port.get(new Random().nextInt(dst_port.size()-1)));
            log.put("username", usernames.get(new Random().nextInt(usernames.size()-1)));
            log.put("domain", domain.get(new Random().nextInt(domain.size()-1)));
            log.put("src_ip", ips.get(new Random().nextInt(ips.size()-1)));
            log.put("dst_ip", ips.get(new Random().nextInt(ips.size()-1)));
            log.put("operation_type", "login");
            log.put("risk_type", riskType);
            log.put("action_result", "failed");
            log.put("operation_time", "2020-02-11 08:12:21");
            log.put("eqpt_device_type", edt.get(new Random().nextInt(edt.size()-1)));
            log.put("raw_log", "2020-02-11 08:12:21 [login] ugi=testxinghuanes result=failed");
//            log.put("create_time", getRangeTimeStamp());
            log.put("create_time", ct[i]);
            log.put("db_name", db_name.get(new Random().nextInt(db_name.size()-1)));
            log.put("operation_target", db_name.get(new Random().nextInt(db_name.size()-1)));
            log.put("index_date", INDEX_DATE);
            logs.add(log);
        }

        return logs;
    }

    public String getRangeTimeStamp(){
        Long currentTimestamps=System.currentTimeMillis();
        Long oneDayTimestamps= Long.valueOf(60*60*24*1000);
        Long startOfTodayTimestamps = currentTimestamps-(currentTimestamps+60*60*8*1000)%oneDayTimestamps;

        Long randonTimeStamp = new Double(startOfTodayTimestamps + (currentTimestamps-startOfTodayTimestamps)*Math.random()).longValue();
        return String.valueOf(randonTimeStamp);
    }
}
